/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version
 * 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for
 * the specific language governing permissions and limitations under the License.
 */

package jmine.tec.test.junit.runner;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

import jmine.tec.test.junit.runner.formatter.JUnitResultFormatter;
import jmine.tec.test.junit.runner.formatter.TestOutputType;

import org.apache.tools.ant.util.KeepAliveOutputStream;

/**
 * <p>
 * A wrapper for the implementations of <code>JUnitResultFormatter</code>. In particular, used as a nested <code>&lt;formatter&gt;</code>
 * element in a <code>&lt;junit&gt;</code> task.
 * <p>
 * For example, <code><pre>
 *       &lt;junit printsummary="no" haltonfailure="yes" fork="false"&gt;
 *           &lt;formatter type="plain" usefile="false" /&gt;
 *           &lt;test name="org.apache.ecs.InternationalCharTest" /&gt;
 *       &lt;/junit&gt;</pre></code> adds a <code>plain</code> type implementation (<code>PlainJUnitResultFormatter</code>) to display the
 * results of the test.
 * <p>
 * Either the <code>type</code> or the <code>classname</code> attribute must be set.
 */
public class FormatterElement {

    private OutputStream out = new KeepAliveOutputStream(System.out);

    private File outFile;

    private boolean useFile = true;

    private final TestOutputType outputType;

    /**
     * Construtor.
     * 
     * @param outputType {@link TestOutputType}
     */
    public FormatterElement(TestOutputType outputType) {
        this.outputType = outputType;
    }

    /**
     * <p>
     * Set the file which the formatte should log to.
     * <p>
     * Note that logging to file must be enabled .
     * 
     * @param file arquivo que deve ser gravado
     */
    void setOutfile(File file) {
        this.outFile = file;
    }

    /**
     * <p>
     * Set output stream for formatter to use.
     * <p>
     * Defaults to standard out.
     * 
     * @param output the output stream to use.
     */
    public void setOutput(OutputStream output) {
        if (output == System.out || output == System.err) {
            this.out = new KeepAliveOutputStream(output);
        } else {
            this.out = output;
        }
    }

    /**
     * Set whether the formatter should log to file.
     * 
     * @param useFile if true use a file, if false send to standard out.
     */
    public void setUseFile(boolean useFile) {
        this.useFile = useFile;
    }

    /**
     * Get whether the formatter should log to file.
     * 
     * @return whether the formatter should log to file.
     */
    boolean getUseFile() {
        return this.useFile;
    }

    /**
     * @return new {@link JUnitResultFormatter} instance
     */
    public JUnitResultFormatter createFormatter() {
        JUnitResultFormatter r = null;
        try {
            r = this.outputType.getFormatterClass().newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        if (this.useFile && this.outFile != null) {
            try {
                this.out = new BufferedOutputStream(new FileOutputStream(this.outFile));
            } catch (java.io.IOException e) {
                throw new RuntimeException(e);
            }
        }
        r.setOutput(this.out);

        return r;
    }

    /**
     * @return {@link TestOutputType}
     */
    public TestOutputType getOutputType() {
        return this.outputType;
    }
}
